package core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import common.Sequence;
import common.Service;
import common.Servlet;
import common.Validate;
import dict.BcDict;
import dict.CbDict;
import dict.CommonDict;
import dict.TransactionDict;
import dicts.GlobalDict;
import dicts.PaymentDict;
import entities.TBank;
import entities.TBc;
import entities.TCb;
import entities.TMerchant;
import entities.TSubject;
import entities.TTransaction;
import interfaces.IBankService;
import interfaces.IBcService;
import interfaces.ICbService;
import interfaces.IMerchantService;
import interfaces.ISubjectService;
import interfaces.ITransactionService;
import net.sf.json.JSONObject;
import util.LogUtil;
import utils.DateUtil;
import utils.DigestUtil;
import utils.NumberUtil;
import utils.StringUtil;

public class Refund extends Servlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public synchronized void process(HttpServletRequest request, HttpServletResponse response) throws Exception {

		System.out.println(DateUtil.format(new Date(), DateUtil.DATETIME) + " | 交易退款");

		// 初始化service
		IMerchantService merchantService = (IMerchantService) Service.create(IMerchantService.class);
		ISubjectService subjectService = (ISubjectService) Service.create(ISubjectService.class);
		IBankService bankService = (IBankService) Service.create(IBankService.class);
		ITransactionService transactionService = (ITransactionService) Service.create(ITransactionService.class);
		IBcService bcService = (IBcService) Service.create(IBcService.class);
		ICbService cbService = (ICbService) Service.create(ICbService.class);

		Map<String, Object> paramMap = Collections.synchronizedMap(new HashMap<String, Object>());
		JSONObject jsonResult = new JSONObject();

		// 初始化bean和属性
		TBank bank = new TBank();
		TSubject subject = new TSubject();
		TMerchant merchant = new TMerchant();
		TTransaction transaction = new TTransaction();
		TBc bc = new TBc();
		TCb cb = new TCb();

		// 验证系统
		if (GlobalDict.LINUX.equalsIgnoreCase(System.getProperty("os.name")) && !CommonDict.HOST.equals(request.getServerName())) {
			response.getWriter().print(Validate.result(TransactionDict.ILLAGEL_ACCESS, TransactionDict.MESSAGES.get(TransactionDict.ILLAGEL_ACCESS)));
			return;
		}

		// 校验参数 ( 名称,值,校验模式,边界 )
		List<Object[]> parameterList = Collections.synchronizedList(new ArrayList<Object[]>());
		parameterList.add(new Object[] { "version", request.getParameter("version"), Validate.NOTEMPTY | Validate.EXCEEDLENGTH, 0, 50 });
		parameterList.add(new Object[] { "no", request.getParameter("no"), Validate.NOTEMPTY | Validate.EXCEEDLENGTH, 5, 6 });
		parameterList.add(new Object[] { "transaction", request.getParameter("transaction"), Validate.NOTEMPTY | Validate.EXCEEDLENGTH, 0, 50 });
		parameterList.add(new Object[] { "percent", request.getParameter("percent"), Validate.NOTEMPTY | Validate.ISNUMBER | Validate.EXCEEDNUMBER, 0, 100 });
		parameterList.add(new Object[] { "remark", request.getParameter("remark"), Validate.NOTEMPTY | Validate.EXCEEDLENGTH, 0, 100 });
		parameterList.add(new Object[] { "signature", request.getParameter("signature"), Validate.NOTEMPTY | Validate.EXCEEDLENGTH, 0, 500 });

		JSONObject validateResult = Validate.validate(parameterList);
		LogUtil.refund(Validate.summary(parameterList));

		if (!StringUtil.isEmpty(validateResult)) {
			System.out.println ( validateResult.toString() ) ;
			response.getWriter().print(validateResult.toString());
			return;
		}
		
		if (!request.getParameter("version").equals(GlobalDict.VERSION)) {
			response.getWriter().print(Validate.result(TransactionDict.VERSION_ERROR, TransactionDict.MESSAGES.get(TransactionDict.VERSION_ERROR)));
			return;
		}

		// 校验子账户存在和状态
		try {
			subject = subjectService.fetch(request.getParameter("no"));
		} catch (Exception e) {
			response.getWriter().print(Validate.result(TransactionDict.SUBJECT_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.SUBJECT_FETCH_EXCEPTION)));
			return;
		}

		if (subject == null) {
			response.getWriter().print(Validate.result(TransactionDict.SUBJECT_NOT_EXIST, TransactionDict.MESSAGES.get(TransactionDict.SUBJECT_NOT_EXIST)));
			return;
		}

		if (!subject.getSubState().equals("1")) {
			response.getWriter().print(Validate.result(TransactionDict.SUBJECT_STATUS_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.SUBJECT_STATUS_EXCEPTION)));
			return;
		}
		
		// 交易商户存在和状态
		try {
			merchant = merchantService.fetch(subject.getSubNo().substring(0, 4));
		} catch (Exception e) {
			response.getWriter().print(Validate.result(TransactionDict.MERCHANT_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.MERCHANT_FETCH_EXCEPTION)));
			return;
		}

		if (merchant == null) {
			response.getWriter().print(Validate.result(TransactionDict.MERCHANT_NOT_EXIST, TransactionDict.MESSAGES.get(TransactionDict.MERCHANT_NOT_EXIST)));
			return;
		}

		if (!merchant.getMerState().equals("1")) {
			response.getWriter().print(Validate.result(TransactionDict.MERCHANT_STATUS_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.MERCHANT_STATUS_EXCEPTION)));
			return;
		}
		
		// 查出对应交易
		try {
			transaction = transactionService.fetch(request.getParameter("transaction"));
		} catch (Exception e) {
			response.getWriter().print(Validate.result(TransactionDict.TRANSACTION_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.TRANSACTION_NOT_EXIST)));
			return;
		}
		if (transaction == null) {
			response.getWriter().print(Validate.result(TransactionDict.TRANSACTION_NOT_EXIST, TransactionDict.MESSAGES.get(TransactionDict.TRANSACTION_NOT_EXIST)));
			return;
		}
		if (!transaction.getTxnState().equals("1")) {
			response.getWriter().print(Validate.result(TransactionDict.TRANSACTION_STATUS_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.TRANSACTION_STATUS_EXCEPTION)));
			return;
		}

		// 出账存在状态(是否之前还有未处理的退款项)
		try {
			paramMap = Collections.synchronizedMap(new HashMap<String, Object>());
			paramMap.put("txnNo", transaction.getTxnNo());
			paramMap.put("cbState", "0");
		} catch (Exception e) {
			response.getWriter().print(Validate.result(CbDict.CB_FETCH_EXCEPTION, CbDict.MESSAGES.get(CbDict.CB_FETCH_EXCEPTION)));
			return;
		}
		
		if (cbService.contain(paramMap)) {
			response.getWriter().print(Validate.result(CbDict.CB_ALREADY_EXIST, CbDict.MESSAGES.get(CbDict.CB_ALREADY_EXIST)));
			return;
		}

		// 入账存在状态
		try {
			paramMap = Collections.synchronizedMap(new HashMap<String, Object>());
			paramMap.put("txnNo", transaction.getTxnNo());
			paramMap.put("bcState", "1");
			bc = bcService.single(paramMap);
		} catch (Exception e) {
			response.getWriter().print(Validate.result(BcDict.BC_FETCH_EXCEPTION, BcDict.MESSAGES.get(BcDict.BC_FETCH_EXCEPTION)));
			return;
		}

		if (bc == null) {
			response.getWriter().print(Validate.result(BcDict.BC_NOT_EXIST, BcDict.MESSAGES.get(BcDict.BC_NOT_EXIST)));
			return;
		}

		if (!bc.getBcState().equals("1")) {
			response.getWriter().print(Validate.result(BcDict.BC_STATUS_EXCEPTION, BcDict.MESSAGES.get(BcDict.BC_STATUS_EXCEPTION)));
			return;
		}

		// 查出对应收单行
		try {
			bank = bankService.fetch(bc.getBnkNo());
		} catch (Exception e) {
			response.getWriter().print(Validate.result(TransactionDict.AGENCY_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.AGENCY_FETCH_EXCEPTION)));
			return;
		}
		if (bank == null) {
			response.getWriter().print(Validate.result(TransactionDict.AGENCY_CONFIGURATION_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.AGENCY_CONFIGURATION_EXCEPTION)));
			return;
		}
		if (!bank.getBnkState().equals("1")) {
			response.getWriter().print(Validate.result(TransactionDict.AGENCY_CLOSED, TransactionDict.MESSAGES.get(TransactionDict.AGENCY_CLOSED)));
			return;
		}

		// 校验数字签名
		if (!DigestUtil.sha256(subject.getSubNo() + transaction.getTxnNo() + NumberUtil.transfer(new Double(request.getParameter("percent"))) + subject.getSubKey()).equalsIgnoreCase(request.getParameter("signature"))) {
			response.getWriter().print(Validate.result(TransactionDict.SIGNATURE_INCORRECT, TransactionDict.MESSAGES.get(TransactionDict.SIGNATURE_INCORRECT)));
			return;
		}

		if (!bank.getBnkPart().equals("1") && new Double(request.getParameter("percent")) != 100) {
			response.getWriter().print(Validate.result(TransactionDict.PART_REFUND_NOT_ACCEPT, TransactionDict.MESSAGES.get(TransactionDict.PART_REFUND_NOT_ACCEPT)));
			return;
		}

		// 退款金额大于剩余金额
		if (NumberUtil.mul(transaction.getTxnAmount(), NumberUtil.div(new Double(request.getParameter("percent")), 100D, 4)) > transaction.getTxnRemain()) {
			response.getWriter().print(Validate.result(TransactionDict.REFUND_AMOUNT_GREATER_THAN_REMAINING, TransactionDict.MESSAGES.get(TransactionDict.REFUND_AMOUNT_GREATER_THAN_REMAINING)));
			return;
		}

		// 把退款记录进行保存等待审核
		try {
			cb.setCbNo(Sequence.cbSequence());
			cb.setCrdNo(bc.getCrdNo());
			cb.setBnkNo(bank.getBnkNo());
			cb.setTxnNo(bc.getTxnNo());
			cb.setCbType(PaymentDict.CB_REFUND);
			cb.setCbOrder(bc.getBcOrder());
			cb.setCbCur(CommonDict.CUR);
			cb.setCbAmount(NumberUtil.mul(bc.getBcAmount(), NumberUtil.div(new Double(request.getParameter("percent")), 100D, 4)));
			cb.setCbMoney(cb.getCbAmount());
			cb.setCbRef(bc.getBcRef());
			cb.setCbCard(bc.getBcCard());
			cb.setCbTime(bc.getBcTime());
			cb.setCbCode(CbDict.CB_SUCCESS);
			cb.setCbMessage(CbDict.MESSAGES.get(CbDict.CB_SUCCESS));
			cb.setCbState("0");
			cb.setCbDate(new Date());
			cb.setCbCstate("0");
			cb.setCbCdate(new Date(0L));
			cb.setCbRemark(request.getParameter("remark"));
			cbService.persist(cb);
		} catch (Exception e) {
			response.getWriter().print(Validate.result(CbDict.CB_PERSIST_EXCEPTION, CbDict.MESSAGES.get(CbDict.CB_PERSIST_EXCEPTION)));
			return;
		}

		jsonResult.put("version", GlobalDict.VERSION);
		jsonResult.put("no", subject.getSubNo());
		jsonResult.put("transaction", transaction.getTxnNo());
		jsonResult.put("serial", cb.getCbNo());
		jsonResult.put("signature", DigestUtil.sha256(jsonResult.getString("no") + jsonResult.getString("serial") + subject.getSubKey()));
		jsonResult.put("code", cb.getCbCode());
		jsonResult.put("message", cb.getCbMessage());

		response.getWriter().print(jsonResult.toString());
		return;

	}
}
